/**
 * 
 */
package bplustree;

import java.util.ListIterator;

import register.Register;
import register.RegisterID;
import sun.security.action.GetBooleanAction;

/**
 * Clase representante de las hojas del arbolB+
 * 
 * Hereda del tipo nodo, agrega atributos para los punteros a las hojas adyacentes
 * Reemplaza métodos del tipo Nodo general y contiene propios
 *
 */
public class Leaf extends Node {

	private int nextLeaf;
	private int previousLeaf;
	
	/**
	 * Constructor, como parámetro necesita saber a que arbol pertenece
	 * 
	 */
	public Leaf(BPlusTree tree) {
		super(0,tree);
		nextLeaf=previousLeaf=this.getPosition();
	}
	
	
	
	/**
	 * @return the nextLeaf
	 */
	public int getNextLeaf() {
		return nextLeaf;
	}



	/**
	 * @param nextLeaf the nextLeaf to set
	 */
	public void setNextLeaf(int nextLeaf) {
		this.nextLeaf = nextLeaf;
	}



	/**
	 * @return the previousLeaf
	 */
	public int getPreviousLeaf() {
		return previousLeaf;
	}



	/**
	 * @param previousLeaf the previousLeaf to set
	 */
	public void setPreviousLeaf(int previousLeaf) {
		this.previousLeaf = previousLeaf;
	}

	/**
	 * Método que devuelve el espacio libre en la hoja. Devuelve el espacio comparando la longitúd de
	 * impresión de los contenidos con el tamaño del nodo.
	 * 
	 * IMPORTANTE! El resultado se calcula dinámicamente, nunca se almacena.
	 * 
	 * @return the free_space
	 */
	public int getFree_space() { 
		ListIterator<Register> iterador=registerList.listIterator();
		free_space=node_size;
		
		free_space--; //corresponde al tamanio del separador de campo
		//free_space-=(getRegister_count()); //hay una variabilidad en la escritura gamma que compenso con esto
										//si lo saco, se sobreescriben hojas
		
		free_space-=Integer.toString(getNextLeaf()).length();
		free_space--;//corresponde al tamanio del separador de campo
		free_space-=Integer.toString(getPreviousLeaf()).length();
		
		free_space--;//corresponde al tamanio del separador de campo
		free_space-=Integer.toString(getRegister_count()).length();//corresponde al contador de registros
		free_space--; //corresponde al tamanio del separador de campo
	
		while(iterador.hasNext()/*&&!registerList.isEmpty()*/){ //El isEmpty es redundante
			free_space-=(iterador.next().writeGamma().length()); //el 1 corresponde al separador de registros
		}
		
		return free_space;
	}

	/**
	 * Inserta un registro en la hoja y lo hace de forma ordenada
	 * Si se produce un overflow, arroja una excepcion a ser catheada por el padre
	 * Si el registro esta duplicado, arroja una excepcion
	 * 
	 */
		
	protected void insert(Register reg) throws NodeOverflowException, DuplicateRegisterException{
		
		int tempPosition=getImmediateLess(reg.getID())+1; //posicion probable de insercion
		boolean isModify=false;
		// Verificacion de unicidad
		if(!registerList.isEmpty() && tempPosition>0){ //cubre el caso de lista vacia y de que el menor sea el ultimo
			if(registerList.get(tempPosition-1).getID().compareTo(reg.getID())==0){
				//throw new DuplicateRegisterException();
				registerList.get(tempPosition-1).merge(reg);//reemplazado para mejorar la performance
				isModify=true;							// Directamente se convierte en modify
			}
		}
		if(!isModify) //is Insert
			registerList.add(tempPosition, reg);
		
		setModified(true); //a esta altura seguro que se modifica
		
		//Verificacion de tamaño
		//insercion directa??
		if(getFree_space()<0){
		//INSERCION CON OVERFLOWWW
			throw new NodeOverflowException();
		}
		
	}
	
	/**
	 * Busca el registro con ID igual al pasado por parametro en la hoja y lo devuelve
	 * También setea el iterador de registro pasado como parámetro para apuntar al registro devuelto
	 * El proposito es permitir el recorrido secuencial a partir del registro buscado
	 */
	
	public Register search(RegisterID ID,RegisterIterator iterator) {
		iterator=new RegisterIterator(this,registerList.listIterator(getImmediateLess(ID)));
		Register salida=registerList.get(getImmediateLess(ID));
		
		//si pide busqueda exacta y no matchea exacto, la salida es null. Si no, esta todo bien
		if(getTree().isExactSearch() && salida.getID().getID().compareTo(ID.getID())!=0)
			salida=null;
		
		return salida;
	}
	
	/**
	 * Devuelve un iterador de registros al primer registro de la hoja
	 * Usado para el listado
	 */
	
	public RegisterIterator firstRegIterator() {
		return new RegisterIterator(this,registerList.listIterator());
	}
	
	/**
	 * Modifica un registro de la hoja
	 * 
	 * Solo a ser llamado cuando se sepa que el registro existe ya que no verifica igualdad
	 * realiza un merge entre los contenidos
	 */
	
	public void modify(Register reg) throws NodeOverflowException {
		int tempPosition = getImmediateLess(reg.getID());
		registerList.get(tempPosition).merge(reg);
		setModified(true); //a esta altura seguro que se modifica
		if(getFree_space()<0){
			//MODIFICACION CON OVERFLOWWW
				throw new NodeOverflowException();
		}
		
	}

}
